package org.sanguine.plugin.timetracker;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.swing.*;

import jsr166e.extra.AtomicDouble;

import org.sanguine.plugin.timetracker.events.*;
import org.sanguine.plugin.timetracker.pojo.Timer;

import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.application.ApplicationManager;

/**
 * Created with IntelliJ IDEA. User: alex Date: 13.02.14 Time: 22:27 SVN $Id$
 */
public class TimerActionHandler extends AnAction implements ActionListener {
    private static final String TIMER_ICON_INACTIVE = "img/harvest-logo-icon-16px-inactive.png";
    private static final String TIMER_ICON_DISABLE = "img/harvest-logo-icon-16px-disable.png";
    private static final String TIMER_ICON_ACTIVE = "img/harvest-logo-icon-16px.png";
    private static final double ONE_MINUTE = 1 / 60.0d;

    private AtomicBoolean timerActive = new AtomicBoolean(false);
    private AtomicDouble activeTimerValue = new AtomicDouble(0d);
    private int activeTimerId = -1;
    private int projectId = -1;
    private int taskId = -1;
    private String notes = "";
    private final TimerComponent timerComponent;
    private Icon myIcon;
    private ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1);

    public TimerActionHandler() {
        super();
        timerComponent = ApplicationManager.getApplication().getComponent(TimerComponent.class);
        timerComponent.addActionListener(this);
        setIcon(TIMER_ICON_DISABLE);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO process events (open home page)
        if (e instanceof StartTimerEvent) {
            Integer projectId = ((StartTimerEvent) e).getProject() == null ? null
                    : ((StartTimerEvent) e).getProject().id;
            Integer taskId = ((StartTimerEvent) e).getTask() == null ? null : ((StartTimerEvent) e).getTask().id;
            String notes = ((StartTimerEvent) e).getNotes() == null ? "" : ((StartTimerEvent) e).getNotes();
            if (projectId != null && taskId != null && notes != null) {
                startTimer(projectId, taskId, notes);
            }
        } else if (e instanceof StopTimerEvent) {
            stopTimer();
        }
    }

    @Override
    public void actionPerformed(AnActionEvent e) {
        if (timerComponent.isAuthenticated()) {
            OpenTimerDialogEvent event = new OpenTimerDialogEvent(this, 0, "", e.getDataContext(), e.getProject(),
                    myIcon);
            timerComponent.processEvent(event);
        }
    }

    @Override
    public void update(AnActionEvent e) {
        super.update(e);
        Presentation presentation = e.getPresentation();
        if (ActionPlaces.MAIN_TOOLBAR.equals(e.getPlace())) {
            String iconPath = timerComponent.isAuthenticated() ? (timerActive.get() ? TIMER_ICON_ACTIVE
                    : TIMER_ICON_INACTIVE) : TIMER_ICON_DISABLE;
            setIcon(iconPath);
            if (myIcon != null)
                presentation.setIcon(myIcon);
        }
        if (timerActive.get()) {
            updateTime(activeTimerValue.floatValue());
        }
    }

    private void setIcon(String iconName) {
        URL iconURL = TimerActionHandler.class.getResource(iconName);
        if (iconURL != null) {
            myIcon = new ImageIcon(iconURL);
        } else {
            myIcon = null;
        }
    }

    private void updateTime(double activeTimerValue) {
        TimerValueUpdatedEvent event = new TimerValueUpdatedEvent(this, 0, "", activeTimerValue);
        timerComponent.processEvent(event);
    }

    private void stopTimer() {
        if (timerActive.get() && timerComponent.isAuthenticated()) {
            try {
                activeTimerValue.set(timerComponent.getTrackerServiceProvider().stopTimer(activeTimerId));
                activeTimerId = -1;
                TimerStoppedEvent event = new TimerStoppedEvent(this, 0, "", activeTimerValue.floatValue());
                timerComponent.processEvent(event);
                timerActive.set(false);
                executor.shutdown();
            } catch (IllegalStateException e) {
                // do nothing
            }
        }
    }

    private void startTimer(Integer projectId, Integer taskId, String notes) {
        if (timerComponent.isAuthenticated()) {
            boolean timerChanged = projectId != this.projectId || taskId != this.taskId || !notes.equals(this.notes);

            if (timerActive.get() && timerChanged) {
                stopTimer();
            }

            if (!timerActive.get()) {
                Timer activeTimer = timerComponent.getTrackerServiceProvider().createTimer(projectId, taskId, notes);
                this.activeTimerId = activeTimer.id;
                this.projectId = projectId;
                this.taskId = taskId;
                this.notes = notes;
                if (activeTimerId >= 0) {
                    timerActive.set(true);
                    activeTimerValue.set(timerComponent.getTrackerServiceProvider().getTimerValue(activeTimerId));
                    TimerStartedEvent event = new TimerStartedEvent(this, 0, "", activeTimerValue.doubleValue());
                    timerComponent.processEvent(event);
                    updateTime(activeTimerValue.doubleValue());
                    runPeriodicTimerValueUpdate();
                }
            }

            TimerStartedEvent event = new TimerStartedEvent(this, 0, "",
                    timerComponent.getTrackerServiceProvider().getTimerValue(activeTimerId));
            timerComponent.processEvent(event);
        }
    }

    private void runPeriodicTimerValueUpdate() {
        executor.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                updateTime(activeTimerValue.addAndGet(ONE_MINUTE));
            }
        }, 1, 1, TimeUnit.MINUTES);
    }
}
